from flask import Flask, render_template, request, jsonify, redirect, url_for
import os
import json
import uuid
import logging
from datetime import datetime, timedelta
from config import get_config
from app import create_app  # 导入create_app函数
from werkzeug.utils import secure_filename
from flask_compress import Compress  # 添加Flask-Compress

# 导入优化模块（如果存在）
try:
    from app_optimizations import apply_optimizations
except ImportError:
    def apply_optimizations(app):
        print("⚠️ 优化模块未找到，跳过应用级优化")
        return app

# 从配置中获取设置
config = get_config()

# 创建应用实例
app = create_app(config)

# 应用优化
app = apply_optimizations(app)

# 初始化Flask-Compress
compress = Compress()
compress.init_app(app)

# 优化压缩设置
app.config['COMPRESS_LEVEL'] = 3
app.config['COMPRESS_MIN_SIZE'] = 500

# 确保上传目录存在
os.makedirs('app/static/uploads', exist_ok=True)
os.makedirs('app/static/uploads/metadata', exist_ok=True)
os.makedirs('logs/completions', exist_ok=True)  # 添加日志目录

# 设置上传目录和元数据目录的配置
app.config['UPLOAD_FOLDER'] = 'app/static/uploads'
app.config['METADATA_FOLDER'] = 'app/static/uploads/metadata'


@app.before_request
def before_request():
    # 如果不是HTTPS请求，重定向到HTTPS
    if not request.is_secure and request.host != '127.0.0.1:5000':
        url = request.url.replace('http://', 'https://', 1)
        return redirect(url, code=301)


@app.route('/')
def index():
    # 获取Prolific相关参数
    prolific_pid = request.args.get('PROLIFIC_PID', '')
    prolific_study_id = request.args.get('STUDY_ID', '')
    prolific_session_id = request.args.get('SESSION_ID', '')

    # 打印配置信息，便于调试
    print(f"当前配置的重复次数: {config.REPETITIONS}, 类型: {type(config.REPETITIONS)}")

    # 将Prolific参数传递给模板，测试平台不检查完成状态
    return render_template('index.html',
                           prolific_pid=prolific_pid,
                           prolific_study_id=prolific_study_id,
                           prolific_session_id=prolific_session_id,
                           platform='test',
                           already_completed=False,
                           completion_message="",
                           repetitions=config.REPETITIONS,  # 添加重复次数配置
                           command_words=config.COMMAND_WORDS,  # 添加指令词列表
                           speeds=config.SPEEDS)  # 添加速度设置


@app.route('/prolific')
def prolific_index():
    # 获取Prolific相关参数
    prolific_pid = request.args.get('PROLIFIC_PID', '')
    prolific_study_id = request.args.get('STUDY_ID', '')
    prolific_session_id = request.args.get('SESSION_ID', '')

    # 打印配置信息，便于调试
    print(f"当前配置的重复次数: {config.REPETITIONS}, 类型: {type(config.REPETITIONS)}")

    # 检查用户是否已完成任务
    already_completed = False
    completion_message = ""

    if prolific_pid:
        already_completed = check_user_already_completed(prolific_pid, prolific_study_id, 'prolific')
        if already_completed:
            completion_message = "您已完成此任务，无需重复提交。"
            # 记录重复访问尝试
            log_incomplete_attempt(prolific_pid, prolific_study_id, prolific_session_id, 'prolific')

    # 将Prolific参数传递给模板，并指定平台为prolific
    return render_template('index.html',
                           prolific_pid=prolific_pid,
                           prolific_study_id=prolific_study_id,
                           prolific_session_id=prolific_session_id,
                           platform='prolific',
                           already_completed=already_completed,
                           completion_message=completion_message,
                           repetitions=config.REPETITIONS,  # 添加重复次数配置
                           command_words=config.COMMAND_WORDS,  # 添加指令词列表
                           speeds=config.SPEEDS)  # 添加速度设置


@app.route('/favicon.ico')
def favicon():
    return app.send_static_file('favicon.ico')


@app.route('/upload', methods=['POST'])
def upload():
    try:
        audio_data = request.files.get('audio')
        metadata_str = request.form.get('metadata')

        if not audio_data:
            return jsonify({'success': False, 'error': '没有接收到音频数据'}), 400

        if not metadata_str:
            return jsonify({'success': False, 'error': '没有接收到元数据'}), 400

        # 解析元数据
        try:
            metadata = json.loads(metadata_str)
        except json.JSONDecodeError:
            return jsonify({'success': False, 'error': '元数据格式错误'}), 400

        # 验证音频格式
        audio_format = metadata.get('audioFormat', {})
        sample_rate = audio_format.get('sampleRate')
        bit_depth = audio_format.get('bitDepth')
        channels = audio_format.get('channels')

        if not all([sample_rate, bit_depth, channels]):
            return jsonify({'success': False, 'error': '音频格式信息不完整'}), 400

        if sample_rate != 16000 or bit_depth != 16 or channels != 1:
            return jsonify({'success': False, 'error': f'音频格式不符合要求，需要16kHz, 16bit, 单声道，实际为{sample_rate}Hz, {bit_depth}bit, {channels}声道'}), 400

        # 验证词段数据
        word_segments = metadata.get('wordSegments', [])
        if not word_segments:
            return jsonify({'success': False, 'error': '没有词段数据'}), 400

        # 检查每个词段是否有必要的信息
        for segment in word_segments:
            if not all(key in segment for key in ['start_time', 'end_time', 'label']):
                return jsonify({'success': False, 'error': '词段数据不完整'}), 400

        # 验证词段数量是否足够
        # 根据配置的重复次数计算最小需要的词段数量
        min_segments = len(config.COMMAND_WORDS) * config.REPETITIONS

        print(f"验证词段数量: 当前={len(word_segments)}, 最小需要={min_segments}, 重复次数={config.REPETITIONS}")

        if len(word_segments) < min_segments:
            return jsonify({'success': False, 'error': f'录音词段数量不足，请完成所有指令词的录制（需要{min_segments}个词段）'}), 400

        # 获取客户端真实IP地址
        client_ip = request.remote_addr
        # 尝试从代理头获取真实IP
        if request.headers.get('X-Forwarded-For'):
            client_ip = request.headers.get('X-Forwarded-For').split(',')[0].strip()
        elif request.headers.get('X-Real-IP'):
            client_ip = request.headers.get('X-Real-IP')

        # 收集服务器端获取的客户端信息
        server_detected_client_info = {
            # 网络信息
            'ip_address': client_ip,
            'forwarded_for': request.headers.get('X-Forwarded-For'),
            'real_ip': request.headers.get('X-Real-IP'),
            'proxy_info': request.headers.get('Via'),
            'user_agent': request.user_agent.string,
            'browser': request.user_agent.browser,
            'browser_version': request.user_agent.version,
            'platform': request.user_agent.platform,
            'language': request.accept_languages.best if request.accept_languages else None,
            'accept_languages': [lang[0] for lang in request.accept_languages] if request.accept_languages else [],

            # 设备类型信息 (从User-Agent推断)
            'is_mobile': request.user_agent.platform in ['android', 'iphone', 'ipad'],
            'is_tablet': 'ipad' in request.user_agent.string.lower() or 'tablet' in request.user_agent.string.lower(),
            'is_pc': not (request.user_agent.platform in ['android', 'iphone', 'ipad'] or 'tablet' in request.user_agent.string.lower()),

            # 请求信息
            'request_method': request.method,
            'request_scheme': request.scheme,
            'request_host': request.host,
            'request_path': request.path,
            'request_is_secure': request.is_secure,
            'request_timestamp': datetime.now().isoformat(),

            # 地理位置信息（可以通过IP查询服务获取，这里仅作为示例）
            'geo_info': {
                'country': 'Unknown',
                'city': 'Unknown',
                'region': 'Unknown',
                'timezone': 'Unknown'
            }
        }

        # 生成唯一文件名
        filename = f"{uuid.uuid4()}.wav"
        filepath = os.path.join('app/static/uploads', filename)

        # 保存音频文件
        audio_data.save(filepath)

        # 保存元数据
        metadata_filename = f"{os.path.splitext(filename)[0]}.json"
        metadata_filepath = os.path.join('app/static/uploads/metadata', metadata_filename)

        # 添加文件信息到元数据
        metadata['filename'] = filename
        metadata['uploadTime'] = datetime.now().isoformat()

        # 添加服务器检测到的客户端信息
        metadata['serverDetectedClientInfo'] = server_detected_client_info

        # 如果客户端提供了设备信息，确保它存在
        if 'deviceInfo' not in metadata:
            metadata['deviceInfo'] = {}

        # 记录Prolific相关信息 - 直接从元数据中获取
        prolific_pid = metadata.get('prolificPID', '')
        prolific_study_id = metadata.get('prolificStudyID', '')
        prolific_session_id = metadata.get('prolificSessionID', '')
        platform = metadata.get('platform', 'test')  # 获取平台信息，默认为test

        # 记录日志，便于调试
        print(f"接收到参数: 平台={platform}")
        if platform == 'prolific':
            print(f"Prolific参数: PID={prolific_pid}, STUDY_ID={prolific_study_id}, SESSION_ID={prolific_session_id}")
        print(f"客户端IP: {client_ip}, 浏览器: {request.user_agent.browser}, 平台: {request.user_agent.platform}")

        # 检查用户是否已经完成任务 - 仅对Prolific平台进行检查
        if platform == 'prolific' and prolific_pid:
            already_completed = check_user_already_completed(prolific_pid, prolific_study_id, platform)
            if already_completed:
                # 记录重复提交尝试
                log_incomplete_attempt(prolific_pid, prolific_study_id, prolific_session_id, platform)
                return jsonify({'success': False, 'error': '您已完成此任务，无需重复提交'}), 400

        # 确保这些字段存在于元数据中 - 仅对Prolific平台
        if platform == 'prolific':
            metadata['prolificPID'] = prolific_pid
            metadata['prolificStudyID'] = prolific_study_id
            metadata['prolificSessionID'] = prolific_session_id

        # 确保平台信息存在
        metadata['platform'] = platform

        with open(metadata_filepath, 'w', encoding='utf-8') as f:
            json.dump(metadata, f, ensure_ascii=False, indent=2)

        # 记录成功完成 - 仅对Prolific平台
        if platform == 'prolific' and prolific_pid:
            log_completion(prolific_pid, prolific_study_id, prolific_session_id, platform)

        # 构建完成URL - 根据平台不同返回不同的URL
        completion_url = ""
        if platform == 'prolific' and prolific_pid:
            # Prolific平台的完成URL
            completion_url = f"https://app.prolific.com/submissions/complete?cc=C6686SEV&PROLIFIC_PID={prolific_pid}&STUDY_ID={prolific_study_id}&SESSION_ID={prolific_session_id}"
        else:
            # 测试平台或其他平台 - 返回到首页
            completion_url = "/"

        return jsonify({
            'success': True,
            'filename': filename,
            'message': '录音上传成功',
            'completionUrl': completion_url,  # 返回完成URL给前端
            'platform': platform  # 返回平台信息
        })
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)}), 500


def check_user_completion(prolific_pid):
    """检查用户是否完成了任务"""
    if not prolific_pid:
        return False

    # 检查是否存在该用户的录音文件
    metadata_dir = os.path.join(app.config['METADATA_FOLDER'])
    if not os.path.exists(metadata_dir):
        return False

    for filename in os.listdir(metadata_dir):
        if filename.endswith('.json'):
            filepath = os.path.join(metadata_dir, filename)
            try:
                with open(filepath, 'r', encoding='utf-8') as f:
                    metadata = json.load(f)
                    if metadata.get('prolificPID') == prolific_pid:
                        # 检查是否有足够的词段数据
                        word_segments = metadata.get('wordSegments', [])

                        # 根据配置的重复次数计算最小需要的词段数量
                        min_segments = len(config.COMMAND_WORDS) * config.REPETITIONS

                        print(f"检查用户完成状态: 用户={prolific_pid}, 词段数量={len(word_segments)}, 最小需要={min_segments}")

                        if len(word_segments) >= min_segments:
                            return True
            except Exception as e:
                print(f"读取元数据文件出错: {e}")

    return False


def check_user_already_completed(prolific_pid, study_id=None, platform='prolific'):
    """检查用户是否已经完成任务（从日志文件中查找）"""
    if not prolific_pid:
        return False

    # 检查特定平台的日志文件
    platform_log_file = os.path.join('logs', 'completions', platform, 'successful_completions.log')
    if os.path.exists(platform_log_file):
        try:
            with open(platform_log_file, 'r', encoding='utf-8') as f:
                for line in f:
                    if f"PID: {prolific_pid}" in line:
                        # 如果提供了study_id，则同时检查study_id
                        if study_id and f"STUDY_ID: {study_id}" not in line:
                            continue
                        return True
        except Exception as e:
            print(f"读取平台日志文件出错: {e}")

    return False


def log_completion(prolific_pid, study_id, session_id, platform):
    """记录成功完成的任务"""
    # 根据平台创建不同的日志目录
    log_dir = os.path.join('logs', 'completions', platform)
    os.makedirs(log_dir, exist_ok=True)
    log_file = os.path.join(log_dir, 'successful_completions.log')

    timestamp = datetime.now().isoformat()
    log_entry = f"{timestamp} - PID: {prolific_pid}, STUDY_ID: {study_id}, SESSION_ID: {session_id}\n"

    with open(log_file, 'a', encoding='utf-8') as f:
        f.write(log_entry)

    # 同时更新completions.json文件
    completions_json = os.path.join('logs', 'completions', 'completions.json')
    completion_data = {}

    # 尝试读取现有数据
    if os.path.exists(completions_json) and os.path.getsize(completions_json) > 0:
        try:
            with open(completions_json, 'r', encoding='utf-8') as f:
                completion_data = json.load(f)
        except json.JSONDecodeError:
            print(f"completions.json格式错误，将创建新文件")
            completion_data = {}

    # 添加或更新用户完成记录
    completion_data[prolific_pid] = {
        'study_id': study_id,
        'session_id': session_id,
        'platform': platform,
        'timestamp': timestamp,
        'completion_time': datetime.now().isoformat()
    }

    # 写回文件
    try:
        with open(completions_json, 'w', encoding='utf-8') as f:
            json.dump(completion_data, f, ensure_ascii=False, indent=2)
        print(f"已更新completions.json: {prolific_pid}")
    except Exception as e:
        print(f"更新completions.json失败: {e}")

    print(f"已记录成功完成: {prolific_pid}, 平台: {platform}")


def log_incomplete_attempt(prolific_pid, study_id, session_id, platform):
    """记录未完成的尝试"""
    # 根据平台创建不同的日志目录
    log_dir = os.path.join('logs', 'completions', platform)
    os.makedirs(log_dir, exist_ok=True)
    log_file = os.path.join(log_dir, 'incomplete_attempts.log')

    timestamp = datetime.now().isoformat()
    log_entry = f"{timestamp} - PID: {prolific_pid}, STUDY_ID: {study_id}, SESSION_ID: {session_id}\n"

    with open(log_file, 'a', encoding='utf-8') as f:
        f.write(log_entry)

    print(f"已记录未完成尝试: {prolific_pid}, 平台: {platform}")


if __name__ == '__main__':
    # 启动Flask应用
    app.run(host=config.HOST, port=config.PORT, ssl_context=config.SSL_CONTEXT, debug=config.DEBUG)
